home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ian & Stuart's Australian Mac: Not for Sale
/
Another.not.for.sale (Australia).iso
/
fade into you
/
getting there
/
Apps
/
MOO-1.7.6.src
/
src
/
vector.c
< prev
next >
Wrap
Text File
|
1994-11-02
|
28KB
|
918 lines
/******************************************************************************
Copyright (c) 1992 Xerox Corporation. All rights reserved.
Portions of this code were written by Stephen White, aka ghond.
Use and copying of this software and preparation of derivative works based
upon this software are permitted. Any distribution of this software or
derivative works must comply with all applicable United States export
control laws. This software is made available AS IS, and Xerox Corporation
makes no warranty about the software, its performance or its conformity to
any specification. Any person obtaining a copy of this software is requested
to send their name and post office or electronic mail address to:
Pavel Curtis
Xerox PARC
3333 Coyote Hill Rd.
Palo Alto, CA 94304
Pavel@Xerox.Com
*****************************************************************************/
#include <ctype.h>
#include "my-string.h"
#include "config.h"
#include "log.h"
#include "storage.h"
#include "utils.h"
#include "vector.h"
enum var_len_type {VL_LABEL, VL_LITERAL, VL_VAR_NAME, VL_FORK};
typedef struct var_len_info *var_len_list; /* array */
typedef struct var_len_info { /* holds data for variable length */
enum var_len_type type; /* data while create bytecodes */
unsigned where; /* where value goes in unexpanded vector */
unsigned value; /* value to possibly be expanded */
/* these are used in mutating value field for labels */
unsigned num_prev_forks; /* number of forks before value */
unsigned num_prev_literals; /* number of literals before value */
unsigned num_prev_var_names; /* number of var names before value */
unsigned num_prev_labels; /* number of labels before value*/
struct var_len_info *next; /* links used while generating */
/* condition arms */
} var_len_info;
unsigned num_var_names; /* number of var names in program */
unsigned num_forks; /* number of forks in program */
Var *literal_list; /* array of literals in program */
unsigned total_literals; /* count of literal uses in program */
unsigned num_literals; /* number of unique literals in program */
unsigned max_literal; /* number of literals allocated */
struct local_env {
var_len_list *vl_list; /* pointer to array of literals */
unsigned top_vl_list;
unsigned max_vl_list;
Byte *bytearray; /* byte vector for this environment */
unsigned top_b;
unsigned max_b;
int num_labels; /* number of labels for current environment */
};
Bytecodes ast2v(Stmt *, struct local_env *);
unsigned generate_stmt (Stmt *, struct local_env *);
unsigned generate_expr (Expr *, struct local_env *);
void fix_labels(Bytecodes *, struct local_env *);
#define HOW_MANY_BYTES(t) (t <= 256 ? 1 : (t <= 256*256 ? 2 : 4))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MAX3(a, b, c) MAX(a, MAX(b, c))
#define MAX4(a, b, c, d) MAX(MAX(a, b), MAX(c, d))
static Bytecodes *return_forks; /* array */
static struct local_env *fork_locals; /* array */
static int num_return_forks;
void
add_forked_vector(Bytecodes bc, struct local_env local)
{
Bytecodes *new_forks =
(Bytecodes *)mymalloc(sizeof (Bytecodes) *
(num_return_forks+1), M_FORK_VECTORS);
struct local_env *new_fork_locals =
(struct local_env *)mymalloc(sizeof (struct local_env) *
(num_return_forks+1), M_BYTECODE_INFO);
if (return_forks != 0) {
int loop;
for (loop = 0; loop < num_return_forks; loop++) {
new_forks[loop] = return_forks[loop];
new_fork_locals[loop] = fork_locals[loop];
}
myfree(return_forks, M_FORK_VECTORS);
myfree(fork_locals, M_BYTECODE_INFO);
}
return_forks = new_forks;
fork_locals = new_fork_locals;
return_forks[num_return_forks] = bc;
fork_locals[num_return_forks++] = local;
}
int
vectorize(Stmt *stmt, Bytecodes *main_vector,
Bytecodes **fork_vectors,
Var **lit_list, unsigned *literal_list_size)
{
Bytecodes bc;
int loop;
struct local_env l_env;
num_var_names = 0;
num_forks = 0;
literal_list = 0;
total_literals = 0;
max_literal = 0;
num_literals = 0;
return_forks = 0;
fork_locals = 0;
num_return_forks = 0;
/* prepare to tree walk */
/* tree walk */
bc = ast2v(stmt, &l_env);
fix_labels(&bc, &l_env);
if (fork_locals) {
for (loop = 0; loop < num_return_forks; loop++) {
fix_labels(&return_forks[loop], &fork_locals[loop]);
}
myfree(fork_locals, M_BYTECODE_INFO);
}
if (num_literals < max_literal) {
Var *new_lits =
(Var *)mymalloc(sizeof(Var) * num_literals, M_LIT_LIST);
if (literal_list != 0) {
int i;
for (i = 0; i < num_literals; i++)
new_lits[i] = literal_list[i];
myfree(literal_list, M_LIT_LIST);
}
literal_list = new_lits;
max_literal = num_literals;
}
*main_vector = bc;
*lit_list = literal_list;
*literal_list_size = num_literals;
*fork_vectors = return_forks;
return num_return_forks;
}
void
emit_byte(Byte what, struct local_env *l_env)
{
int i;
if (l_env->top_b == l_env->max_b) {
int new_size = (l_env->bytearray == 0 ? 50 : 2 * l_env->max_b);
Byte *new_b = (Byte *) mymalloc(new_size, M_BYTECODES);
if (l_env->bytearray != 0) {
for (i = 0; i < l_env->top_b; i++)
new_b[i] = l_env->bytearray[i];
myfree(l_env->bytearray, M_BYTECODES);
}
l_env->max_b = new_size;
l_env->bytearray = new_b;
}
l_env->bytearray[l_env->top_b++] = what;
}
void
emit_extended_byte(Byte what, struct local_env *l_env)
{
emit_byte(OP_EXTENDED, l_env);
emit_byte(what, l_env);
}
void
free_vl_list(var_len_list *vl_list, int length)
{
if (vl_list) {
int i;
for (i = 0; i < length; i++)
myfree(vl_list[i], M_VL_VALUE);
myfree(vl_list, M_VL_LIST);
}
}
void
fix_labels(Bytecodes *bc, struct local_env *l_env)
{
int byte_loop, new_byte_index = 0, var_len_index = 0;
int value, size = 1, new_size;
Byte *new_bytes;
bc->numbytes_fork = HOW_MANY_BYTES(num_forks);
bc->numbytes_literal = HOW_MANY_BYTES(num_literals);
bc->numbytes_var_name = HOW_MANY_BYTES(num_var_names);
new_size = bc->size + (bc->numbytes_label - 1) * bc->num_labels +
(bc->numbytes_fork - 1) * num_forks +
(bc->numbytes_var_name - 1) * num_var_names +
(bc->numbytes_literal - 1) * total_literals;
new_bytes = (Byte *) mymalloc(new_size, M_BYTECODES);
for (byte_loop = 0; byte_loop < bc->size; byte_loop++)
if (var_len_index < l_env->top_vl_list &&
byte_loop == l_env->vl_list[var_len_index]->where) {
var_len_info *vl_info = l_env->vl_list[var_len_index];
value = vl_info->value;
switch (vl_info->type) {
case VL_LABEL:
size = bc->numbytes_label;
value +=
vl_info->num_prev_forks * (bc->numbytes_fork-1) +
vl_info->num_prev_labels * (bc->numbytes_label-1) +
vl_info->num_prev_var_names * (bc->numbytes_var_name-1) +
vl_info->num_prev_literals * (bc->numbytes_literal-1);
break;
case VL_FORK:
size = bc->numbytes_fork;
break;
case VL_LITERAL:
size = bc->numbytes_literal;
break;
case VL_VAR_NAME:
size = bc->numbytes_var_name;
break;
}
if (size == 1)
new_bytes[new_byte_index] = value & 0377;
else {
if (size == 2) {
new_bytes[new_byte_index] = (value >> 8) & 0377;
new_bytes[new_byte_index+1] = value & 0377;
} else { /* numbytes == 4 */
new_bytes[new_byte_index] = (value >> 24);
new_bytes[new_byte_index+1] = (value >> 16) & 0377;
new_bytes[new_byte_index+2] = (value >> 8) & 0377;
new_bytes[new_byte_index+3] = value & 0377;
}
}
new_byte_index += size;
var_len_index++;
} else
new_bytes[new_byte_index++] = bc->vector[byte_loop];
myfree(bc->vector, M_BYTECODES);
free_vl_list(l_env->vl_list, l_env->top_vl_list);
bc->vector = new_bytes;
bc->size = new_size;
}
Bytecodes
ast2v(Stmt *stmt, struct local_env *l_env)
{
Bytecodes bc;
l_env->top_vl_list = 0;
l_env->max_vl_list = 0;
l_env->vl_list = 0;
l_env->top_b = 0;
l_env->max_b = 0;
l_env->bytearray = 0;
l_env->num_labels = 0;
bc.max_stack = generate_stmt(stmt, l_env);
emit_byte(OP_DONE, l_env); /* append OP_DONE at the end */
bc.size = l_env->top_b;
bc.vector = l_env->bytearray;
if (bc.size <= 256)
bc.numbytes_label = 1;
else {
if (bc.size + l_env->num_labels > 256*256)
bc.numbytes_label = 4;
else
bc.numbytes_label = 2;
}
bc.num_labels = l_env->num_labels;
return bc;
}
unsigned
continue_args(Arg_List *args, struct local_env *l_env)
{
unsigned max_s, max_s1;
if (args)
switch (args->kind) {
case ARG_NORMAL:
max_s = generate_expr(args->expr, l_env);
emit_byte(OP_LIST_ADD_TAIL, l_env);
max_s1 = continue_args(args->next, l_env);
return MAX(max_s, max_s1);
break;
case ARG_SPLICE:
max_s = generate_expr(args->expr, l_env);
emit_byte(OP_LIST_APPEND, l_env);
max_s1 = continue_args(args->next, l_env);
return MAX(max_s, max_s1);
break;
};
return 0;
}
unsigned
generate_arg_list(Arg_List *args, struct local_env *l_env)
{
unsigned max_s, max_s1;
if (args)
switch (args->kind) {
case ARG_NORMAL:
max_s = generate_expr(args->expr, l_env);
emit_byte(OP_MAKE_SINGLETON_LIST, l_env);
max_s1 = continue_args(args->next, l_env);
return MAX(max_s, 1 + max_s1);
break;
case ARG_SPLICE:
max_s = generate_expr(args->expr, l_env);
emit_byte(OP_CHECK_LIST_FOR_SPLICE, l_env);
max_s1 = continue_args(args->next, l_env);
return MAX(max_s, 1 + max_s1);
break;
}
else {
emit_byte(OP_MAKE_EMPTY_LIST, l_env);
return 1;
}
errlog("generate_arg_list didn't return a valid value!\n");
return -1;
}
var_len_info *
push_vl_info(enum var_len_type type, int where, int value,
var_len_info *v, struct local_env *l_env)
{
var_len_info *vli;
if (l_env->top_vl_list == l_env->max_vl_list) {
unsigned i, new_size =
l_env->max_vl_list ? 2 * l_env->max_vl_list : 50;
var_len_list *new_vll =
mymalloc(sizeof(var_len_list) * new_size, M_VL_LIST);
if (l_env->vl_list) {
for (i = 0; i < l_env->top_vl_list; i++)
new_vll[i] = l_env->vl_list[i];
myfree(l_env->vl_list, M_VL_LIST);
}
l_env->max_vl_list = new_size;
l_env->vl_list = new_vll;
}
vli = l_env->vl_list[l_env->top_vl_list] =
mymalloc(sizeof(var_len_info), M_VL_VALUE);
if (v) {
*vli = *v;
vli->where = where;
} else {
vli->where = where;
vli->type = type;
vli->num_prev_forks = num_forks;
vli->num_prev_literals = num_literals;
vli->num_prev_var_names = num_var_names;
vli->num_prev_labels = l_env->num_labels;
vli->value = value;
}
l_env->top_vl_list++;
emit_byte(value, l_env);
return vli;
}
var_len_info *
push_label(var_len_info *v, struct local_env *l_env)
{
var_len_info *ret = push_vl_info(VL_LABEL, l_env->top_b, 128, v, l_env);
l_env->num_labels++;
return ret;
}
void
update_label(var_len_info *lab, struct local_env *l_env)
{
lab->type = VL_LABEL;
lab->num_prev_forks = num_forks;
lab->num_prev_literals = num_literals;
lab->num_prev_var_names = num_var_names;
lab->num_prev_labels = l_env->num_labels;
lab->value = l_env->top_b;
}
void
push_literal(int slot, struct local_env *l_env)
{
(void) push_vl_info(VL_LITERAL, l_env->top_b, slot, 0, l_env);
}
void
push_fork(Stmt *stmt, struct local_env *l_env)
{
struct local_env forked_env;
Bytecodes bc;
bc = ast2v(stmt, &forked_env);
add_forked_vector(bc, forked_env);
(void) push_vl_info(VL_FORK, l_env->top_b, num_forks++, 0, l_env);
}
void
push_var_name(int slot, struct local_env *l_env)
{
(void) push_vl_info(VL_VAR_NAME, l_env->top_b, slot, 0, l_env);
num_var_names++;
}
int
get_lit_slot(Var v)
{
int i;
total_literals++;
for (i = 0; i < num_literals; i++)
if (v.type == TYPE_STR && literal_list[i].type == TYPE_STR) {
if (!strcmp(v.v.str, literal_list[i].v.str))
return i;
} else
if (equality(v, literal_list[i]))
return i;
/* new literal */
/* check if size of list needs to grow */
if (num_literals == max_literal) {
int new_size = (max_literal ? max_literal * 2 : 10);
Var *new_lits = (Var *)mymalloc(sizeof(Var) * new_size, M_LIT_LIST);
if (literal_list != 0) {
for (i = 0; i < num_literals; i++)
new_lits[i] = literal_list[i];
myfree(literal_list, M_LIT_LIST);
}
max_literal = new_size;
literal_list = new_lits;
}
literal_list[num_literals] = var_ref(v);
return num_literals++;
}
void
handle_variable(enum Opcode op, int slot, struct local_env *l_env)
{
if (slot >= NUM_READY_VARS) {
emit_byte(op + NUM_READY_VARS, l_env);
push_var_name(slot, l_env);
} else
emit_byte(op + slot, l_env);
}
unsigned
generate_ref_stack(Expr *stack, struct local_env *l_env, int *num_refs)
{
int ans = 0;
unsigned max_s1, max_s2, max_s;
switch (stack->kind) {
case EXPR_INDEX:
max_s1 = generate_ref_stack(stack->e.bin.lhs, l_env, &ans);
max_s2 = generate_expr(stack->e.bin.rhs, l_env);
emit_byte(OP_PUSH_REF, l_env);
max_s = max_s1 + max_s2 + 1;
/* max will sometime be greater than absolute minimum needed */
/* if stack->e.bin.lhs has a max_stack > 3 for EXPR_PROP or */
/* EXPR_INDEX, max_s will be larger than needed by a small */
/* amount, but making the adjustment would cost more than it */
/* would save. */
break;
case EXPR_PROP:
if (stack->e.bin.lhs->kind == EXPR_VAR && /* handle $prop case */
stack->e.bin.rhs->kind == EXPR_VAR &&
stack->e.bin.lhs->e.var.type == TYPE_OBJ &&
stack->e.bin.lhs->e.var.v.obj == 0)
(void) get_lit_slot(stack->e.bin.rhs->e.var);
max_s1 = generate_expr(stack->e.bin.lhs, l_env);
max_s2 = generate_expr(stack->e.bin.rhs, l_env);
emit_byte(OP_PUSH_GET_PROP, l_env);
max_s = MAX3(max_s1, 1 + max_s2, 3);
break;
default:
max_s = generate_expr(stack, l_env);
}
*num_refs = 1 + ans;
return max_s;
}
void
push_ref(Expr *e, struct local_env *l_env)
{
switch(e->kind) {
case EXPR_PROP:
emit_byte(OP_PUT_PROP, l_env);
break;
case EXPR_INDEX:
push_ref(e->e.bin.lhs, l_env);
break;
case EXPR_ID:
handle_variable(OP_PUT, e->e.id.slot, l_env);
break;
default:
errlog("Illegal expression on lhs.");
}
}
unsigned
generate_expr(Expr *expr, struct local_env *l_env)
{
int top_id, num_refs;
var_len_info *info1, *info2;
unsigned max_s1, max_s2, max_s3, max_s4;
switch (expr->kind) {
case EXPR_VAR:
if (expr->e.var.type == TYPE_NUM &&
IN_OPTIM_NUM_RANGE(expr->e.var.v.num))
emit_byte(OPTIM_NUM_TO_OPCODE(expr->e.var.v.num), l_env);
else {
emit_byte(OP_IMM, l_env);
push_literal(get_lit_slot(expr->e.var), l_env);
}
return 1;
break;
case EXPR_ID:
handle_variable(OP_PUSH, expr->e.id.slot, l_env);
return 1;
break;
case EXPR_PROP:
if (expr->e.bin.lhs->kind == EXPR_VAR && /* handle $prop case */
expr->e.bin.rhs->kind == EXPR_VAR &&
expr->e.bin.lhs->e.var.type == TYPE_OBJ &&
expr->e.bin.lhs->e.var.v.obj == 0)
(void) get_lit_slot(expr->e.bin.rhs->e.var);
max_s1 = generate_expr(expr->e.bin.lhs, l_env);
max_s2 = generate_expr(expr->e.bin.rhs, l_env);
emit_byte(OP_GET_PROP, l_env);
return MAX(max_s1, 1 + max_s2);
break;
case EXPR_VERB:
max_s1 = generate_expr(expr->e.verb.obj, l_env);
if (expr->e.verb.verb->kind == EXPR_VAR &&
(expr->e.verb.verb->e.var.type == TYPE_STR &&
(isalpha(expr->e.verb.verb->e.var.v.str[0]) ||
expr->e.verb.verb->e.var.v.str[0] == '_'))) {
/* handle obj:vrb(args) */
emit_byte(OP_IMM, l_env);
top_id = l_env->top_vl_list;
push_literal(128, l_env);
max_s2 = 1;
max_s3 = generate_arg_list(expr->e.verb.args, l_env);
l_env->vl_list[top_id]->value =
get_lit_slot(expr->e.verb.verb->e.var);
} else {
max_s2 = generate_expr(expr->e.verb.verb, l_env);
max_s3 = generate_arg_list(expr->e.verb.args, l_env);
}
emit_byte(OP_CALL_VERB, l_env);
return MAX3(max_s1, 1 + max_s2, 2 + max_s3);
break;
case EXPR_INDEX:
max_s1 = generate_expr(expr->e.bin.lhs, l_env);
max_s2 = generate_expr(expr->e.bin.rhs, l_env);
emit_byte(OP_REF, l_env);
return MAX(max_s1, 1 + max_s2);
break;
case EXPR_RANGE:
max_s1 = generate_expr(expr->e.range.base, l_env);
max_s2 = generate_expr(expr->e.range.from, l_env);
max_s3 = generate_expr(expr->e.range.to, l_env);
emit_byte(OP_RANGE_REF, l_env);
return MAX3(max_s1, 1 + max_s2, 2 + max_s3);
break;
case EXPR_ASGN:
switch(expr->e.asgn.kind) {
case ASGN_VAR:
max_s1 = generate_expr(expr->e.asgn.value, l_env);
handle_variable(OP_PUT, expr->e.asgn.a.id.slot, l_env);
return max_s1;
break;
case ASGN_PROP:
/* to handle $prop case */
if (expr->e.asgn.a.bin.lhs->kind == EXPR_VAR &&
expr->e.asgn.a.bin.rhs->kind == EXPR_VAR &&
expr->e.asgn.a.bin.lhs->e.var.type == TYPE_OBJ &&
expr->e.asgn.a.bin.lhs->e.var.v.obj == 0)
(void) get_lit_slot(expr->e.asgn.a.bin.rhs->e.var);
max_s1 = generate_expr(expr->e.asgn.a.bin.lhs, l_env);
max_s2 = generate_expr(expr->e.asgn.a.bin.rhs, l_env);
max_s3 = generate_expr(expr->e.asgn.value, l_env);
emit_byte(OP_PUT_PROP, l_env);
return MAX3(max_s1, 1 + max_s2, 2 + max_s3);
break;
case ASGN_REF:
max_s1 = generate_ref_stack(expr->e.asgn.a.bin.lhs,
l_env, &num_refs);
max_s2 = generate_expr(expr->e.asgn.a.bin.rhs, l_env);
max_s3 = generate_expr(expr->e.asgn.value, l_env);
emit_byte(OP_PUT_TEMP, l_env);
while (num_refs--)
emit_byte(OP_INDEXSET, l_env);
push_ref(expr->e.asgn.a.bin.lhs, l_env);
emit_byte(OP_POP, l_env);
emit_byte(OP_PUSH_TEMP, l_env);
return MAX(max_s1 + max_s2, max_s1 + 1 + max_s3);
break;
case ASGN_RANGE:
max_s1 = generate_ref_stack(expr->e.asgn.a.range.base, l_env,
&num_refs);
max_s2 = generate_expr(expr->e.asgn.a.range.from, l_env);
max_s3 = generate_expr(expr->e.asgn.a.range.to, l_env);
max_s4 = generate_expr(expr->e.asgn.value, l_env);
emit_byte(OP_PUT_TEMP, l_env);
emit_extended_byte(OP_RANGESET, l_env);
while (--num_refs) /* subtract first here */
emit_byte(OP_INDEXSET, l_env);
push_ref(expr->e.asgn.a.range.base, l_env);
emit_byte(OP_POP, l_env);
emit_byte(OP_PUSH_TEMP, l_env);
return MAX3(max_s1 + max_s2, max_s1 + 1 + max_s3,
max_s1 + 2 + max_s4);
break;
}
break;
case EXPR_CALL:
max_s1 = generate_arg_list(expr->e.call.args, l_env);
emit_byte(OP_BI_FUNC_CALL, l_env);
emit_byte(expr->e.call.func, l_env);
return MAX(max_s1, 1);
break;
case EXPR_PLUS:
case EXPR_MINUS:
case EXPR_TIMES:
case EXPR_DIVIDE:
case EXPR_MOD:
case EXPR_EQ:
case EXPR_NE:
case EXPR_LT:
case EXPR_LE:
case EXPR_GT:
case EXPR_GE:
case EXPR_IN:
max_s1 = generate_expr(expr->e.bin.lhs, l_env);
max_s2 = generate_expr(expr->e.bin.rhs, l_env);
switch(expr->kind) {
case EXPR_PLUS: emit_byte(OP_ADD, l_env); break;
case EXPR_MINUS: emit_byte(OP_MINUS, l_env); break;
case EXPR_TIMES: emit_byte(OP_MULT, l_env); break;
case EXPR_DIVIDE: emit_byte(OP_DIV, l_env); break;
case EXPR_MOD: emit_byte(OP_MOD, l_env); break;
case EXPR_EQ: emit_byte(OP_EQ, l_env); break;
case EXPR_NE: emit_byte(OP_NE, l_env); break;
case EXPR_LT: emit_byte(OP_LT, l_env); break;
case EXPR_LE: emit_byte(OP_LE, l_env); break;
case EXPR_GT: emit_byte(OP_GT, l_env); break;
case EXPR_GE: emit_byte(OP_GE, l_env); break;
case EXPR_IN: emit_byte(OP_IN, l_env); break;
default: ;
}
return MAX(max_s1, 1 + max_s2);
break;
case EXPR_AND:
case EXPR_OR:
max_s1 = generate_expr(expr->e.bin.lhs, l_env);
switch(expr->kind) {
case EXPR_AND:
emit_byte(OP_AND, l_env);
break;
case EXPR_OR:
emit_byte(OP_OR, l_env);
break;
default: ;
}
info1 = push_label(0, l_env);
max_s2 = generate_expr(expr->e.bin.rhs, l_env);
update_label(info1, l_env);
return MAX(max_s1, max_s2);
break;
case EXPR_NEGATE:
max_s1 = generate_expr(expr->e.bin.lhs, l_env);
emit_byte(OP_UNARY_MINUS, l_env);
return max_s1;
break;
case EXPR_NOT:
max_s1 = generate_expr(expr->e.bin.lhs, l_env);
emit_byte(OP_NOT, l_env);
return max_s1;
break;
case EXPR_LIST:
return generate_arg_list(expr->e.list, l_env);
break;
case EXPR_COND:
max_s1 = generate_expr(expr->e.cond.condition, l_env);
emit_byte(OP_IF_QUES, l_env);
info1 = push_label(0, l_env);
max_s2 = generate_expr(expr->e.cond.consequent, l_env);
emit_byte(OP_JUMP, l_env);
info2 = push_label(0, l_env);
update_label(info1, l_env);
max_s3 = generate_expr(expr->e.cond.alternate, l_env);
update_label(info2, l_env);
return MAX3(max_s1, max_s2, max_s3);
break;
default: ;
}
return 0;
}
var_len_info *
generate_cond_arm(Cond_Arm *arm, Stmt *otherwise,
struct local_env *l_env, unsigned *max_s)
{
var_len_info *info1, *info2;
unsigned max_s1, max_s2, max_s3 = 0;
max_s1 = generate_expr(arm->condition, l_env);
emit_byte(OP_EIF, l_env);
info1 = push_label(0, l_env); /* add label for else[if] part */
max_s2 = generate_stmt(arm->stmt, l_env);
emit_byte(OP_JUMP, l_env);
info2 = push_label(0, l_env); /* add label for COND exit */
update_label(info1, l_env); /* fill in else[if] label */
if (arm->next) {
info1 = generate_cond_arm(arm->next, otherwise, l_env, &max_s3);
info2->next = info1;
*max_s = MAX3(max_s1, max_s2, max_s3);
return info2;
} else if (otherwise)
max_s3 = generate_stmt(otherwise, l_env);
info2->next = 0;
*max_s = MAX3(max_s1, max_s2, max_s3);
return info2;
}
unsigned
generate_stmt(Stmt *s, struct local_env *l_env)
{
Stmt *stmt = s;
var_len_info *info1, *info2;
var_len_info tmp;
unsigned stmt_list_max_s = 0, this_stmt_max_s, max_s1, max_s2, max_s3;
while (stmt) {
this_stmt_max_s = 0;
switch (stmt->kind) {
case STMT_COND:
max_s1 = generate_expr(stmt->s.cond.arms->condition, l_env);
emit_byte(OP_IF, l_env);
info1 = push_label(0, l_env); /* add label for else[if] part */
max_s2 = generate_stmt(stmt->s.cond.arms->stmt, l_env);
emit_byte(OP_JUMP, l_env);
info2 = push_label(0, l_env); /* add label for COND exit */
update_label(info1, l_env); /* fill in else[if] label */
info1 = 0;
max_s3 = 0;
if (stmt->s.cond.arms->next) {
info1 = generate_cond_arm(stmt->s.cond.arms->next,
stmt->s.cond.otherwise,
l_env, &max_s3);
} else if (stmt->s.cond.otherwise)
max_s3 = generate_stmt(stmt->s.cond.otherwise, l_env);
while (info1) {
update_label(info1, l_env);
info1 = info1->next;
}
update_label(info2, l_env);
this_stmt_max_s = MAX3(max_s1, max_s2, max_s3);
break;
case STMT_LIST:
max_s1 = generate_expr(stmt->s.list.expr, l_env);
/* add a constant 1 for some reason or other */
emit_byte(124, l_env);
update_label(&tmp, l_env);
emit_byte(OP_FOR_LIST, l_env);
push_var_name(stmt->s.list.id.slot, l_env);
info1 = push_label(0, l_env);
max_s2 = generate_stmt(stmt->s.list.body, l_env);
emit_byte(OP_JUMP, l_env);
info2 = push_label(&tmp, l_env); /* add address of loop start */
update_label(info1, l_env);
this_stmt_max_s = MAX(max_s1, 2 + max_s2);
break;
case STMT_RANGE:
max_s1 = generate_expr(stmt->s.range.from, l_env);
max_s2 = generate_expr(stmt->s.range.to, l_env);
update_label(&tmp, l_env);
emit_byte(OP_FOR_RANGE, l_env);
push_var_name(stmt->s.range.id.slot, l_env);
info1 = push_label(0, l_env);
max_s3 = generate_stmt(stmt->s.range.body, l_env);
emit_byte(OP_JUMP, l_env);
info2 = push_label(&tmp, l_env);
update_label(info1, l_env);
this_stmt_max_s = MAX3(max_s1, 1 + max_s2, 2 + max_s3);
break;
case STMT_WHILE:
update_label(&tmp, l_env);
max_s1 = generate_expr(stmt->s.loop.condition, l_env);
emit_byte(OP_WHILE, l_env);
info1 = push_label(0, l_env); /* add exit from while loop */
max_s2 = generate_stmt(stmt->s.loop.body, l_env);
emit_byte(OP_JUMP, l_env);
info2 = push_label(&tmp, l_env);
update_label(info1, l_env);
this_stmt_max_s = MAX(max_s1, max_s2);
break;
case STMT_FORK:
max_s1 = generate_expr(stmt->s.fork.time, l_env);
if (stmt->s.fork.id.name == 0)
emit_byte(OP_FORK, l_env);
else
emit_byte(OP_FORK_WITH_ID, l_env);
push_fork(stmt->s.fork.body, l_env);
if (stmt->s.fork.id.name != 0)
push_var_name(stmt->s.fork.id.slot, l_env);
this_stmt_max_s = max_s1;
break;
case STMT_EXPR:
this_stmt_max_s = generate_expr(stmt->s.expr, l_env);
emit_byte(OP_POP, l_env);
break;
case STMT_RETURN:
if (!(stmt->s.expr)) {
emit_byte(OP_RETURN0, l_env);
this_stmt_max_s = 0;
} else {
this_stmt_max_s = generate_expr(stmt->s.expr, l_env);
emit_byte(OP_RETURN, l_env);
}
break;
}
stmt_list_max_s = MAX(stmt_list_max_s, this_stmt_max_s);
stmt = stmt->next;
}
return stmt_list_max_s;
}
char rcsid_vector[] = "$Id: vector.c,v 1.13 1992/10/23 23:03:47 pavel Exp $";
/* $Log: vector.c,v $
* Revision 1.13 1992/10/23 23:03:47 pavel
* Added copyright notice.
*
* Revision 1.12 1992/10/23 22:23:32 pavel
* Eliminated all uses of the useless macro NULL.
*
* Revision 1.11 1992/10/21 03:02:35 pavel
* Converted to use new automatic configuration system.
*
* Revision 1.10 1992/10/17 20:58:01 pavel
* Global rename of strdup->str_dup, strref->str_ref, vardup->var_dup, and
* varref->var_ref.
*
* Revision 1.9 1992/09/24 02:38:46 pjames
* Fixed bug where number of unique literals in program was used to
* increase byte code size, instead of number of literals used in
* program.
*
* Revision 1.8 1992/08/28 23:16:40 pjames
* Added `emit_extended_byte()' for new opcodes.
* Added ASGN_RANGE code generation.
*
* Revision 1.7 1992/08/28 16:00:17 pjames
* Changed vardup to varref.
*
* Revision 1.6 1992/08/12 01:53:55 pjames
* EXPR_NEGATE case no longer needs to convert negative literals to
* optimized numbers, because they will be caught in EXPR_VAR.
*
* Revision 1.5 1992/08/10 16:26:24 pjames
* Updated #includes
*
* Revision 1.4 1992/07/30 21:26:08 pjames
* Added max_stack calculation (from parser.y).
*
* Revision 1.3 1992/07/27 18:26:19 pjames
* Change ct_env to var_names, const_env to literals, f_vectors to
* fork_vectors, removed global stack of local_ens. Improved readability
* of code.
*
* Revision 1.2 1992/07/21 00:08:03 pavel
* Added rcsid_<filename-root> declaration to hold the RCS ident. string.
*
* Revision 1.1 1992/07/20 23:23:12 pavel
* Initial RCS-controlled version.
*/